from flask import current_app, request, jsonify
from functools import wraps
from app.models.user import User
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, BadSignature, SignatureExpired
from flask_login import login_user, current_user
from app.models.article import Article


def generate_token(user):
    expitation = 3600
    s = Serializer(current_app.config['SECRET_KEY'], expires_in=expitation)
    token = s.dumps({'id': user.id}).decode('ascii')
    return token, expitation


def validate_token(token):
    s = Serializer(current_app.config['SECRET_KEY'])
    try:
        data = s.loads(token)
    except (BadSignature, SignatureExpired):
        return False
    if login_user(User.query.get_or_404(data['id'])):
        current_app.logger.info('验证token成功，并登陆login_user')
    return True


def get_token():
    if 'Authorization' in request.headers:
        try:
            token_type, token = request.headers['Authorization'].split(None, 1)
        except ValueError:
            token_type = token = None
    else:
        token_type = token = None
    return token_type, token


def auth_required(f):
    """验证token授权认证"""
    wraps(f)

    def decorated(*args, **kwargs):
        token_type, token = get_token()
        if request.method != 'OPTIONS':
            if token_type != 'Bearer':
                return jsonify(success=False, message="授权头不对")
            if token is None:
                return jsonify(success=False, message="没有授权信息")
            if not validate_token(token):
                return jsonify(success=False, message="授权失败", code=1001)
        return f(*args, **kwargs)

    return decorated


def auth_self_required(f):
    """验证是否是自已用户的权限"""
    wraps(f)

    def decorated(*args, **kwargs):
        model = Article.query.get_or_404(kwargs.get('id'))
        if current_user.role.name in ['Administrator', 'Leadership', 'Head', 'Audit']:
            return f(*args, **kwargs)
        if model.user != current_user:
            return jsonify(success=False, message="没有权限", code=403)
        return f(*args, **kwargs)
    return decorated
